package com.rose.springbootgeneratefile.internal;

import com.rose.springbootgeneratefile.api.*;
import com.rose.springbootgeneratefile.api.dom.DefaultJavaFormatter;
import com.rose.springbootgeneratefile.codegen.mybatis3.IntrospectedTableMyBatis3Impl;
import com.rose.springbootgeneratefile.config.Context;
import com.rose.springbootgeneratefile.config.JavaTypeResolverConfiguration;
import com.rose.springbootgeneratefile.config.TableConfiguration;
import com.rose.springbootgeneratefile.internal.types.JavaTypeResolverDefaultImpl;
import com.rose.springbootgeneratefile.utils.StringUtility;

import java.util.ArrayList;
import java.util.List;

public class ObjectFactory {
    private static List<ClassLoader> externalClassLoaders;

    static {
        externalClassLoaders = new ArrayList<ClassLoader>();
    }

    /**
     * 在外部的classloader中查找字节码文件
     * @param type
     * @return
     * @throws ClassNotFoundException
     */
    public static Class<?> externalClassForName(String type)
            throws ClassNotFoundException {

        Class<?> clazz;

        for (ClassLoader classLoader : externalClassLoaders) {
            try {
                clazz = Class.forName(type, true, classLoader);
                return clazz;
            } catch (Throwable e) {
                // ignore - fail safe below
            }
        }

        return internalClassForName(type);
    }

    /**
     * 实例化数据库表列对象
     * @param context
     * @return
     */
    public static IntrospectedColumn createIntrospectedColumn(Context context) {
        String type = context.getIntrospectedColumnImpl();
        if (!StringUtility.stringHasValue(type)) {
            type = IntrospectedColumn.class.getName();
        }

        IntrospectedColumn answer = (IntrospectedColumn) createInternalObject(type);
        answer.setContext(context);

        return answer;
    }

    /**
     * 根据类型名称实例化
     * @param type
     * @return
     */
    public static Object createInternalObject(String type) {
        Object answer;

        try {
            Class<?> clazz = internalClassForName(type);

            answer = clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("根据类型实例化代码失败"); //$NON-NLS-1$

        }

        return answer;
    }
    /**
     * 获取字节码
     * @param type
     * @return
     * @throws ClassNotFoundException
     */
    public static Class<?> internalClassForName(String type)
            throws ClassNotFoundException {
        Class<?> clazz = null;

        try {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            clazz = Class.forName(type, true, cl);
        } catch (Exception e) {
            // ignore - failsafe below
        }

        if (clazz == null) {
            clazz = Class.forName(type, true, ObjectFactory.class.getClassLoader());
        }

        return clazz;
    }

    /**
     * 生成映射table表数据的类
     * @param tableConfiguration
     * @param table
     * @param context
     * @return
     */
    public static IntrospectedTable createIntrospectedTable(
            TableConfiguration tableConfiguration, FullyQualifiedTable table,
            Context context) {

        IntrospectedTable answer = createIntrospectedTableForValidation(context);
        answer.setFullyQualifiedTable(table);
        answer.setTableConfiguration(tableConfiguration);

        return answer;
    }

    /**
     * 生成映射table表数据的具体类
     * @param context
     * @return
     */
    public static IntrospectedTable createIntrospectedTableForValidation(Context context) {
        String type = context.getTargetRuntime();
        if (!StringUtility.stringHasValue(type)) {
            type = IntrospectedTableMyBatis3Impl.class.getName();
//        } else if ("Ibatis2Java2".equalsIgnoreCase(type)) { //$NON-NLS-1$
//            type = IntrospectedTableIbatis2Java2Impl.class.getName();
//        } else if ("Ibatis2Java5".equalsIgnoreCase(type)) { //$NON-NLS-1$
//            type = IntrospectedTableIbatis2Java5Impl.class.getName();
//        } else if ("Ibatis3".equalsIgnoreCase(type)) { //$NON-NLS-1$
//            type = IntrospectedTableMyBatis3Impl.class.getName();
//        } else if ("MyBatis3".equalsIgnoreCase(type)) { //$NON-NLS-1$
//            type = IntrospectedTableMyBatis3Impl.class.getName();
//        } else if ("MyBatis3Simple".equalsIgnoreCase(type)) { //$NON-NLS-1$
//            type = IntrospectedTableMyBatis3SimpleImpl.class.getName();
        }

        IntrospectedTable answer = (IntrospectedTable) createInternalObject(type);
        answer.setContext(context);

        return answer;
    }

    /**
     * 获取到生成注解类的具体实现类
     * @param context
     * @return
     */
    public static CommentGenerator createCommentGenerator(Context context) {

//        CommentGeneratorConfiguration config = context
//                .getCommentGeneratorConfiguration();
        CommentGenerator answer;

        String type;
//        if (config == null || config.getConfigurationType() == null) {
            type = DefaultCommentGenerator.class.getName();
//        } else {
//            type = config.getConfigurationType();
//        }

        answer = (CommentGenerator) createInternalObject(type);

//        if (config != null) {
//            answer.addConfigurationProperties(config.getProperties());
//        }

        return answer;
    }

    /**
     * 创建java代码格式化工具实例
     * @param context
     * @return
     */
    public static JavaFormatter createJavaFormatter(Context context) {
        String type = context.getProperty(PropertyRegistry.CONTEXT_JAVA_FORMATTER);
        if (!StringUtility.stringHasValue(type)) {
            type = DefaultJavaFormatter.class.getName();
        }

        JavaFormatter answer = (JavaFormatter) createInternalObject(type);

        answer.setContext(context);

        return answer;
    }

    /**
     * 创建java字段类型解析器实例
     * @param context
     * @return
     */
    public static JavaTypeResolver createJavaTypeResolver(Context context) {
        JavaTypeResolverConfiguration config = context
                .getJavaTypeResolverConfiguration();
        String type;

        if (config != null && config.getConfigurationType() != null) {
            type = config.getConfigurationType();
            if ("DEFAULT".equalsIgnoreCase(type)) { //$NON-NLS-1$
                type = JavaTypeResolverDefaultImpl.class.getName();
            }
        } else {
            type = JavaTypeResolverDefaultImpl.class.getName();
        }

        JavaTypeResolver answer = (JavaTypeResolver) createInternalObject(type);
//        answer.setWarnings(warnings);

        if (config != null) {
            answer.addConfigurationProperties(config.getProperties());
        }

        answer.setContext(context);

        return answer;
    }
}
